/*
 * Copyright 2009, Team Mondegreen:
 * Brian Hsieh - bh2181@columbia.edu
 * Eugene Yao - eyy2102@columbia.edu
 * Jake Amonette - jaa2149@columbia.edu
 * Tal Giat - tg2235@colubia.edu
 * 
 * This file is part of AMFM (A Minimal Fractal Music Language), a language created for
 * fractal music as part of the Programming Languages and Translator class at Columbia university.
 *
 * For more details go to: http://code.google.com/p/amfm/
 * 
 * AMFM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option any later version.
 * 
 * AMFM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with AMFM.  If not, see <http://www.gnu.org/licenses/>. 
 */

/**
 * AMFM error handler registers all compilation errorsMessages and translates them to messages when they are requested.
 * 
 * @author talgiat
 */
package org.mondegreen.amfm.compiler;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

/**
 * Global compilation error manager. We store all our error messages templates in a file, and collect all the
 * errorsMessages that occur during compilation using this manager. When the manager registers an error message
 * it receives a list of arguments that is used to fill the error message template/format to generate the final
 * error message. Another nice feature is that all error messages can have a prefix string that is defined in the
 * error messages file under the "prefix" property. In our case it is the emoticon :( 
 * The reason to have multiple errorsMessages
 * is that during the actual lexing and parsing stages we might encounter minor syntactic errorsMessages that
 * we can recover from and thus we want to give all these errorsMessages we encountered to the user so the
 * compilation process will be easier instead of stopping always on the first error. So errorsMessages however
 * will be fatal and will stop the compilation such as not being able to find the source file, read it, or
 * write the final output. In any case the AmFmCopiler decided what to do with errorsMessages and it uses this
 * manager to output the error messages that the manager collected.
 * 
 * @author talgiat
 */
public class AmFmErrorManager {
  private ResourceBundle errorMessagesResource;
  private String messagePrefix;
  private List<String> errorsMessages;

  /**
   * Default constructor: loads error messages templates, and initializes error queue.
   */
  public AmFmErrorManager() {
    errorMessagesResource = ResourceBundle.getBundle(getClass().getPackage().getName() + ".ErrorMessages");
    try {
      messagePrefix = errorMessagesResource.getString("prefix");
    } catch (MissingResourceException e) {
      messagePrefix = "";
    }
    resetMessages(); // Set the message to new empty list
  }

  /**
   * Adds an error to the error messages list that are accumulated during compilation.
   * 
   * @param errorCode the message error code @see AmFmErrorCode
   * @param args a variable list of message arguments to fill in the message template with
   * @see MessageFormat#format(String pattern, Object ... arguments) format
   */
  public void addError(AmFmErrorCode errorCode, Object... args) {
    if (errorCode == null || errorMessagesResource.getString(errorCode.toString()) == null) {
      throw new IllegalArgumentException("Passed illegal error message code");
    }
    String errorMessageTemplate = errorMessagesResource.getString(errorCode.toString());
    String formattedErrorMessage = MessageFormat.format(errorMessageTemplate, args);
    // Add error message prefix
    if (!messagePrefix.trim().isEmpty()) {
      formattedErrorMessage = messagePrefix + " " + formattedErrorMessage;
    }
    errorsMessages.add(formattedErrorMessage);
  }
  
  /**
   * @return true if the manager collected at least one error message, false if it has none
   */
  public boolean hasErrorMessages() {
    return errorsMessages.size() > 0;
  }

  /**
   * Returns an unmodifiable list of the error message that were registered during compilation according to
   * the order they occurred during compilation.
   * 
   * @return an unmodifiable list of error messages
   */
  public List<String> getErrorMessages() {
    return Collections.unmodifiableList(errorsMessages);
  }

  /**
   * Set the error message to new empty list removing all the saved messages in the manager. This should be
   * used if we use the manager through multiple compilations. Each time we start compilation we reset it.
   */
  public void resetMessages() {
    errorsMessages = new LinkedList<String>();
  }
}